package com.dingwen.stusprboomon.aspect;

import com.dingwen.stusprboomon.annotation.ParamCheckAnnotation;
import com.dingwen.stusprboomon.constant.eum.ParamEnum;
import com.dingwen.stusprboomon.util.ParamCheckUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

/**
 * 参数校验切面
 *
 * @author dingwen
 * 2021.06.24 11:02
 */
@Aspect
@Component
public class ParamCheckAspect {
    /**
     * 方法入参检查工具
     */
    private final ParamCheckUtil paramCheckUtil = ParamCheckUtil.getInstance();

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(com.dingwen.stusprboomon.annotation.ParamCheckAnnotation)")
    public void paramCheckPointCut() {

    }


    /**
     * 环绕通知处理参数
     *
     * @param proceedingJoinPoint 进行连接点
     * @return {@link Object}
     */
    @Around(value = "paramCheckPointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        Object proceed = null;
        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        // 具体方法
        Method method = methodSignature.getMethod();
        // 方法上的日志切面注解
        ParamCheckAnnotation paramCheckAnnotation = method.getAnnotation(ParamCheckAnnotation.class);
        // 注解值集合
        List<ParamEnum> paramEnumList = Arrays.asList(paramCheckAnnotation.value());
        // 获取请求参数
        Object[] args = proceedingJoinPoint.getArgs();

        Stream.iterate(0, i -> i + 1).limit(paramEnumList.size()).forEach(index -> {
            args[index] = paramCheckUtil.append(paramEnumList.get(index), args[index]);
        });

        try {
            proceed = proceedingJoinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            //TODO AOP 方法异常
        }
        return proceed;
    }

}
